<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">

    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <title>标注操作</title>

    <script src="../js/vue.min.js"></script>
    <script src="../js/slc-utils.js"></script>
    <script src="../js/view-display-anim.js"></script>
    <script src="../js/platform.js"></script>

    <script src="../js/es-module-shims.js"></script>
    <script type="importmap">
        {
          "imports": {
            "three": "../js/three.module.min.js"
          }
        }
    </script>
    <script type="module" src="../js/model-viewer.min.js"></script>
    <script type="module" src="../js/model-viewer-effects.min.js"></script>
    <!--<script type="importmap">
        {
          "imports": {
            "three": "https://cdn.jsdelivr.net/npm/three@^0.157.0/build/three.module.min.js"
          }
        }
    </script>
    <script type="module" src="https://cdn.jsdelivr.net/npm/@google/model-viewer/dist/model-viewer-module.min.js"></script>
    <script type="module" src="https://cdn.jsdelivr.net/npm/@google/model-viewer-effects/dist/model-viewer-effects.min.js"></script>-->
    <style>
        .v-box {
            display: flex;
            flex-direction: column;
        }

        .h-box {
            display: flex;
            flex-direction: row;
            justify-content: start;
            align-items: start;
        }

        .slc-display:not([slc-display]) {
            display: none !important;
        }

        #app {
            height: 100vh;
            background-color: #00000000;
            position: relative
        }

        #video {
            width: 100vw;
            height: 100vh;
            position: absolute;
        }

        /*热点*/
        .hotspot {
            display: block;
            width: 32px;
            height: 32px;
            border: none;
            background: radial-gradient(circle at center, #ffffff80 0% 15%, transparent 15% 22%, #ffffff80 22% 30%, transparent 30% 100%);
            border-radius: 50%;
            box-sizing: border-box;
            --min-hotspot-opacity: 0;
        }

        .hotspot-line {
            stroke: rgba(255, 255, 255, 0.4);
            stroke-width: 2;
            /*stroke-dasharray: 2*/
        }

        /*线条*/
        .line-container {
            pointer-events: none;
            display: block;
        }

        /*标签容器*/
        .label-container {
            pointer-events: none;
            display: block;
        }

        /*标签*/
        /*pointer-events: auto;*/
        .hotspot-label {
            pointer-events: none;
            position: absolute;
            background-color: transparent;
            user-select: none;
            display: flex;
            flex-direction: row;
        }

        .hotspot-label > * {
            pointer-events: auto;
        }

        .hotspot-label-ornament {
            pointer-events: auto;
            justify-content: start;
            align-items: start;
            color: white;
            font-size: 15px;
            padding: 0.5em 1em;
            display: block;
            border-image-slice: 47 47 47 47 fill;
            border-image-width: 20px 20px 20px 20px;
            border-image-outset: 0px 0px 0px 0px;
            border-image-source: url("../assets/images/main_biz_bg_model_part_info.png");
        }

        /*热点成员的显示和隐藏*/
        .hotspot-member-hide {
            visibility: hidden;
        }

        :not(:defined) > * {
            display: none;
        }

        /*工具栏*/
        .utils-container {
            display: block;
        }

        .utils-bottom-bar {
            pointer-events: none;
            position: absolute;
            left: 24px;
            bottom: 24px;
            right: 24px;
            align-items: center;
        }

        .utils-bottom-bar > * {
            pointer-events: auto;
        }


        .utils-check {
            width: 16px;
            height: 16px;
        }

        .debug-div {
            position: absolute;
            bottom: 0;
            right: 0;
            width: 36px;
            height: 36px;
            user-select: none; /* 禁止文本选中 */
            -webkit-user-select: none; /* Safari 兼容 */
            -moz-user-select: none; /* Firefox 兼容 */
        }

        input[type="checkbox"] {
            /* 隐藏原生样式 */
            width: 20px;
            height: 20px;
            border: 2px solid white;
        }

        /*编辑热点视图*/
        .edit-hotspot-parent {
            width: 100%;
            position: absolute;
            top: 0;
            bottom: 0;
            background-color: #00000040;
        }

        .edit-hotspot-parent > div {
            position: relative;
            top: 50%;
            left: 50%;
            width: 600px;
            height: auto;
            transform: translateX(-50%) translateY(-50%);
            background-color: white;
            border-radius: 8px;
            padding: 16px;
            box-shadow: 0 0 16px rgba(0, 0, 0, 1);
        }

        .edit-hotspot-parent > div label {
            font-size: 16px
        }

        .edit-hotspot-parent > div input {
            flex: 1;
            font-size: 16px;
            margin-top: 2px;
            padding: 4px 4px;
        }


    </style>
</head>
<body style="margin: 0;padding: 0">
<div id="app" class="v-box">
    <!--
    camera-controls：启用相机控制
    camera-orbit="45deg 55deg 4m"：相机的初始位置
    camera-target="0m 0m 0m"：设置模型中心点
    max-camera-orbit="auto auto 300%"：最大相机轨道
    min-camera-orbit="auto auto 300%"：最小相机轨道
    interaction-prompt="none"：交互提示 关闭 auto开启
    disable-tap：禁用点击
    autoplay：自动播放动画
    auto-rotate：自动旋转
    shadow-intensity：阴影强度
    scale="1 1 1"：缩放x y z全部填写一样无效
    touch-action="pan-y" ：交互提示
    -->
    <model-viewer
            ref="reveal"
            id="reveal"
            camera-controls
            autoplay
            disable-tap
            loading="eager"
            touch-action="none"
            shadow-intensity="1"
            max-camera-orbit="auto auto 300%"
            interaction-prompt="none"
            interpolation-decay="108"
            :camera-orbit="modelInfo.cameraOrbit"
            :field-of-view="modelInfo.fieldOfView"
            :camera-target="modelInfo.cameraTarget"
            :src="modelInfo.pathByHtml"
            alt="A 3D model of a shishkebab"
            @click="onModelViewerClick"
            @mousedown="onModelViewerDown"
            @mouseleave="onModelViewerEnd"
            @mouseup="onModelViewerEnd"
            @touchstart="onModelViewerDown"
            @touchend="onModelViewerEnd"
            @touchcancel="onModelViewerEnd"
            style="width: 100%; height: 100%;background-color: unset;">
        <svg id="lines" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" class="line-container"
             v-if="modelInfo.showHotspotEnable">
            <polyline v-for="hotspotLine in modelInfo.hotspotList" points="" :id="'line-'+hotspotLine.slot"
                      class="hotspot-line hotspot-member-hide"
                      fill="none"/>
            <!--<polyline id="line-hotspot1" class="hotspot-line" fill="none" points=""/>-->
        </svg>
        <button v-if="modelInfo.showHotspotEnable" v-for="hotspotLine in modelInfo.hotspotList"
                :id="'button-'+hotspotLine.slot"
                :slot="hotspotLine.slot"
                :data-surface="hotspotLine.dataSurface"
                class="hotspot" data-visibility-attribute="visible" data-visible>
        </button>
        <div class="label-container" v-if="modelInfo.showHotspotEnable">
            <div v-for="hotspotLine in modelInfo.hotspotList"
                 class="h-box hotspot-label hotspot-member-hide">
                <div class="hotspot-label-ornament"
                     :id="'label-'+hotspotLine.slot"
                     :slot="hotspotLine.slot"
                     @click="onClickHotspotLabel"
                     @mousedown="onDragHotspotLabelStart"
                     @mousemove="onDragHotspotLabelRun"
                     @mouseup="onDragHotspotLabelEnd"
                     @mouseleave="onDragHotspotLabelRun">
                    {{ hotspotLine.title }}<br/>{{ hotspotLine.introduction }}
                </div>
                <div v-if="editHotspotModel" class="v-box" style="align-items: center;justify-content: center;">
                    <img src="../assets/images/main_biz_ic_edit.png" width="20px"
                         height="20px" alt="编辑模型"
                         @click="editHotspotInfo(hotspotLine)"/>
                    <img src="../assets/images/main_biz_ic_remove.png" width="20px"
                         height="20px" alt="移除模型"
                         @click="onRemoveHotspot(hotspotLine)"/>
                </div>
            </div>
        </div>
    </model-viewer>

    <div class="utils-container">
        <!--暂时不显示-->
        <div class="v-box slc-display" style="position: absolute;top: 24px;left:24px;" :slc-display="mainTitle">
            <div style="position: relative;color:white;font-size: 28px;font-weight: bold">{{mainTitle}}</div>
        </div>
        <div class="h-box utils-bottom-bar">
            <input type="checkbox" id="hotspotSwitch" class="slc-display" :slc-display="debugModel" v-if="debugModel" v-model="editHotspotModel" @change="editHotspotModelChange">
            <label  v-if="debugModel"  class="slc-display" :slc-display="debugModel" for="hotspotSwitch" style="color: white">编辑热点</label>
            </input>
            <button v-if="debugModel"  class="slc-display" :slc-display="debugModel" style="margin-left: 16px" @click="onPrintConfig">输出相机参数</button>
            <div style="flex: 1"></div>
            <div @click="onRecoverModel" style="position: relative;margin-top: 8px">
                <img src="../assets/images/main_biz_ic_recover.png" width="32px" height="32px" alt="复位模型">
            </div>
        </div>
        <!--禁止文本选中：user-select 通用；-webkit-user-select Safari 兼容；-moz-user-select Firefox 兼容  -->
        <div class="debug-div" @click="onDebugClick"></div>
    </div>
    <div v-if="debugModel&&currentEditHotspotInfo" class="edit-hotspot-parent slc-display" :slc-display="debugModel&&currentEditHotspotInfo">
        <div class="v-box">
            <div class="h-box">
                <label style="font-size: 20px">{{editHotspotDialogLabel}}</label>
            </div>
            <div class="v-box" style="flex: 1;margin-top: 24px">
                <div class="v-box">
                    <label>热点名称：</label>
                    <input v-model="currentEditHotspotInfo.title"/>
                </div>
                <div class="v-box" style="margin-top: 16px">
                    <label>热点介绍：</label>
                    <input v-model="currentEditHotspotInfo.introduction"/>
                </div>
                <div class="v-box" style="margin-top: 16px">
                    <label>横向相对位置：</label>
                    <input v-model="currentEditHotspotInfo.labelX"/>
                </div>
                <div class="v-box" style="margin-top: 16px">
                    <label>纵向相对位置：</label>
                    <input v-model="currentEditHotspotInfo.labelY"/>
                </div>
                <div class="v-box" style="margin-top: 16px">
                    <label>dataSurface：</label>
                    <input :disabled="true" v-model="currentEditHotspotInfo.dataSurface"/>
                </div>
                <div class="v-box" style="margin-top: 16px">
                    <label>cameraOrbit：</label>
                    <input :disabled="true" v-model="currentEditHotspotInfo.cameraOrbit"/>
                </div>
                <div class="v-box" style="margin-top: 16px">
                    <label>fieldOfView：</label>
                    <input :disabled="true" v-model="currentEditHotspotInfo.fieldOfView"/>
                </div>
                <div class="v-box" style="margin-top: 16px">
                    <label>cameraTarget：</label>
                    <input :disabled="true" v-model="currentEditHotspotInfo.cameraTarget"/>
                </div>
            </div>
            <div class="h-box" style="justify-content:end;margin-top: 24px">
                <button @click="onSaveHotspot" style="margin-right: 16px">保存</button>
                <button @click="onCancelAddEditHotspot">关闭</button>
            </div>
        </div>
    </div>
</div>
</body>
<script type="module">
    new Vue({
        el: '#app',
        data() {
            return {
                mainTitle: '预览模式',//操作标题
                debugModel: false,//调试模式
                debugClickCountProxy: null,//调试模式点击代理
                showCameraView: false,//显示相机画面
                editHotspotModel: false,//编辑热点模式
                circulateShowHotspot: false,//是否循环展示热点，默认值，会被覆盖
                viewDisplayAnim: null,//视图展示动画
                hotspotLabelRects: null,//热点label矩形范围
                modelViewerRect: null,//热点容器
                draggingHotspotLabel: false,//拖动热点标签
                currentShowHotspotIndex: null,//当前展示的热点，仅在circulateShowHotspot为true时生效
                modelInfo: null,//模型信息
                currentEditHotspotInfo: null,//当前添加或编辑的热点
                editHotspotDialogLabel: null//热点信息对话框标题
            }
        },
        created() {
            const params = getUrlParams()
            const modelInfoStr = params.get('modelInfo')
            this.onLoadModel(modelInfoStr)
        },
        mounted() {
            this.onRegister()
            //赋值给window调用
            window.vueOnLoadModel = this.onLoadModel
        },
        beforeDestroy() {
            // 在组件销毁之前，删除事件监听器以避免内存泄漏
            //window.removeEventListener('resize', this.updateHotspotLabelRect);
        },
        methods: {
            //获取模型视图
            getModelViewer() {
                return this.$refs.reveal;
            },
            //获取热点
            getHotspotElement(hotspotSlot) {
                return this.getModelViewer().querySelector('#button-' + hotspotSlot)
            },
            //该热点对应的线
            getHotspotLine(hotspotSlot) {
                return this.getModelViewer().querySelector('#line-' + hotspotSlot)
            },
            //该热点对应的label
            getHotspotLabel(hotspotSlot) {
                return this.getModelViewer().querySelector('#label-' + hotspotSlot)
            },
            //隐藏热点成员
            showHotspotMember(hotspotMember, display) {
                if (display) {
                    //直接移除隐藏class
                    hotspotMember.classList.remove('hotspot-member-hide')
                } else {
                    //如果是隐藏事件且是隐藏的则不处理
                    if (this.hotspotMemberHasHide(hotspotMember)) {
                        return;
                    }
                    hotspotMember.classList.add('hotspot-member-hide')
                }
            },
            //自动隐藏热点成员
            autoShowHotspotMember(hotspotMember) {
                if (this.hotspotMemberHasHide(hotspotMember)) {
                    console.log('自动显示热点成员：' + hotspotMember.id)
                    this.showHotspotMember(hotspotMember, true)
                } else {
                    console.log('自动隐藏热点成员：' + hotspotMember.id)
                    this.showHotspotMember(hotspotMember, false)
                }
            },
            //热点成员是否隐藏
            hotspotMemberHasHide(hotspotMember) {
                return hotspotMember.classList.contains('hotspot-member-hide')
            },
            //更新热点标签矩形
            fillHotspotLabelRect() {
                this.getModelViewer().querySelectorAll('.hotspot-label').forEach((item, index) => {
                    this.hotspotLabelRects[item.slot] = item.getBoundingClientRect()
                })
            },
            //更新热点位置
            updateHotspotLabelLocation(hotspotLabel, left, top) {
                if (hotspotLabel) {
                    hotspotLabel.parentElement.style.left = left + 'px';
                    hotspotLabel.parentElement.style.top = top + 'px';
                }
            },
            //画线
            drawLine(hotspotData, hotspotLine, hotspotLabel, labelRect) {
                const hotspot = this.getModelViewer().queryHotspot(hotspotData.slot);
                if (hotspot == null) {
                    return
                }
                let points = hotspot.canvasPosition.x + ',' + hotspot.canvasPosition.y
                points += ' '
                points += (labelRect.left + labelRect.width / 2) + ',' + (labelRect.top + labelRect.height / 2)
                hotspotLine.setAttribute('points', points);
                //根据相机的可见度来控制显示和隐藏
                if (!hotspot.facingCamera) {
                    this.showHotspotMember(hotspotLine, false)
                    this.showHotspotMember(hotspotLabel.parentElement, false)
                } else {
                    //如果不是手动控制模式才自动显示和隐藏点
                    if (!this.circulateShowHotspot) {
                        this.showHotspotMember(hotspotLine, true)
                        this.showHotspotMember(hotspotLabel.parentElement, true)
                    }
                }
            },
            //明确当前显示的热点
            explicitCurrentShowHotspotIndex(targetIndex) {
                //不是循环显示直接返回
                if (!this.circulateShowHotspot) {
                    return
                }
                //复制当前显示热点的位置
                if (targetIndex != null) {
                    this.currentShowHotspotIndex = targetIndex
                }
                //初始化默认位置
                if (this.currentShowHotspotIndex == null) {
                    this.currentShowHotspotIndex = 0
                }
                //遍历热点
                this.modelInfo.hotspotList.forEach((item, index) => {
                    const line = this.getHotspotLine(item.slot);
                    const label =  this.getHotspotLabel(item.slot);
                    //当前要显示的热点下标等于遍历的下标
                    this.showHotspotMember(line, index === this.currentShowHotspotIndex)
                    this.showHotspotMember(label.parentElement, index === this.currentShowHotspotIndex)
                })
                //热点显示位置++，如果大于热点列表则从头开始
                this.currentShowHotspotIndex++
                if (this.currentShowHotspotIndex >= this.modelInfo.hotspotList.length) {
                    this.currentShowHotspotIndex = 0
                }
            },
            //取消视图显示消失动画
            cancelViewDisplayAnim() {
                if (this.viewDisplayAnim != null) {
                    this.viewDisplayAnim.cancelDelayedTaskFlash()
                }
            },
            //开始视图显示消失动画
            startViewDisplayAnim() {
                if (this.viewDisplayAnim == null) {
                    //间隔大于0才创建
                    if (this.modelInfo.opacityAnimPeriod && this.modelInfo.opacityAnimPeriod > 0) {
                        this.viewDisplayAnim = new ViewDisplayAnim(this.getModelViewer())
                        this.viewDisplayAnim.initialDelay = this.modelInfo.opacityAnimInitialDelay ? this.modelInfo.opacityAnimInitialDelay : 0
                        this.viewDisplayAnim.period = this.modelInfo.opacityAnimPeriod
                        this.viewDisplayAnim.onTaskRun = (initialRun, currentDisplay) => {
                            //是初始化或不是调试模式则恢复模型位置
                            if (initialRun && !this.debugModel) {
                                this.onRecoverModel()
                            }
                            //当前未显示且是循环显示热点模式
                            if (!currentDisplay && this.circulateShowHotspot) {
                                this.explicitCurrentShowHotspotIndex()
                            }
                        }
                    }
                } else {
                    this.cancelViewDisplayAnim()
                }
                if (this.viewDisplayAnim) {
                    this.viewDisplayAnim.startDelayedTaskFlash()
                }
            },
            //模块鼠标按下事件
            onModelViewerClick(event) {
                if (this.debugModel) {
                    const position = this.getModelViewer().surfaceFromPoint(event.clientX, event.clientY)
                    if (!position) {
                        return
                    }
                    console.log(position)
                    //如果是编辑热点模式
                    if (this.editHotspotModel) {
                        this.addHotspotInfo(position)
                    }
                }
            },
            //模块鼠标按下事件
            onModelViewerDown(event) {
                this.cancelViewDisplayAnim()
            },
            //模块鼠标按下结束
            onModelViewerEnd(event) {
                if (this.viewDisplayAnim != null) {
                    this.viewDisplayAnim.startDelayedTaskFlash()
                }
            },
            //点击热点label
            onClickHotspotLabel(event) {
                const hotspotLabel = event.target
                if (!hotspotLabel.slot) {
                    return
                }
                const hotspotLabelTemp = this.hotspotLabelRects[hotspotLabel.slot]
                const labelX = hotspotLabelTemp.left / (this.modelViewerRect.width - hotspotLabelTemp.width)
                const labelY = hotspotLabelTemp.top / (this.modelViewerRect.height - hotspotLabelTemp.height)
                console.log('热点名称：' + hotspotLabel.title.trim() + '\n'
                    + '热点介绍: ' + hotspotLabel.introduction + '\n'
                    + 'labelX: ' + labelX + '\n'
                    + 'labelY: ' + labelY)
            },
            //热点label拖动开始
            onDragHotspotLabelStart(event) {
                const hotspotLabel = event.target
                if (!hotspotLabel.slot) {
                    return
                }
                this.draggingHotspotLabel = true;
            },
            //热点label拖动中
            onDragHotspotLabelRun(event) {
                const hotspotLabel = event.target
                if (!hotspotLabel.slot) {
                    return
                }
                if (this.draggingHotspotLabel) {
                    const hotspotLabelRect = this.hotspotLabelRects[hotspotLabel.slot]
                    const newX = event.clientX - this.modelViewerRect.left - hotspotLabelRect.width / 2
                    const newY = event.clientY - this.modelViewerRect.top - hotspotLabelRect.height / 2
                    this.updateHotspotLabelLocation(hotspotLabel, newX, newY)
                }
            },
            //热点label拖动结束
            onDragHotspotLabelEnd(event) {
                const hotspotLabel = event.target
                if (!hotspotLabel.slot) {
                    return
                }
                this.draggingHotspotLabel = false;
                const targetSlot = hotspotLabel.slot
                let targetHotspot = this.modelInfo.hotspotList.find((item, index) => {
                    return item.slot === targetSlot
                })
                const rect = this.hotspotLabelRects[targetSlot];
                targetHotspot.labelX = rect.left / (this.modelViewerRect.width)
                targetHotspot.labelY = rect.top / (this.modelViewerRect.height)
            },
            //加载相机
            loadCamera() {
                if (!this.showCameraView) {
                    return
                }
                getVideoInput((videoInputs) => {
                    let video = this.$refs.video;
                    let videoRect = video.getBoundingClientRect()
                    const videoConfig = getVideoSize(videoRect.width, videoRect.height)
                    if (platform.os.family === 'iOS' || platform.os.family === 'Android') {
                        //手机使用此种方法
                        videoConfig.facingMode = 'environment'
                    } else {
                        //PC使用此种方法
                        let videoId
                        if (videoInputs.length === 1) {
                            videoId = videoInputs[0].deviceId
                        } else {
                            videoId = videoInputs[videoInputs.length - 1].deviceId
                        }
                        videoConfig.deviceId = videoId
                    }
                    getCameraStream(videoConfig, (stream) => {
                        video.srcObject = stream;
                        video.play();
                    }, (error) => {
                        console.log(`访问用户媒体设备失败${error.name}, ${error.message}`);
                    })
                })
            },
            //初始化热点
            registerHotspotList() {
                if (this.modelInfo.showHotspotEnable) {
                    //遍历所有热点
                    this.modelInfo.hotspotList.forEach((item, index) => {
                        this.updateHotspotLabelLocation(
                            this.getHotspotLabel(item.slot),
                            item.labelX * this.modelViewerRect.width,
                            item.labelY * this.modelViewerRect.height)
                        //设置热点点击事件
                        let hotspotElement = this.getHotspotElement(item.slot)
                        //现移除旧的
                        if (item.elementClickListener != null) {
                            hotspotElement.removeEventListener('click', item.elementClickListener);
                        }
                        //将点击事件保存在item中，因为需要移除重新使用
                        item.elementClickListener = (event) => {
                            console.log('点击了热点：' + event.target.id)
                            this.explicitCurrentShowHotspotIndex(index)
                            if (item.cameraOrbit != null && item.fieldOfView != null) {
                                this.getModelViewer().cameraOrbit = item.cameraOrbit
                                this.getModelViewer().fieldOfView = item.fieldOfView
                            }
                            if (item.cameraTarget != null) {
                                this.getModelViewer().cameraTarget = item.cameraTarget
                            }
                        }
                        hotspotElement.addEventListener('click', item.elementClickListener);
                    })
                }
            },
            //注册监听
            onRegister() {
                //模型加载成功监听
                this.getModelViewer().addEventListener('load', () => {
                    //此处延时是为了方式this.getModelViewer().getBoundingClientRect()获取不正确
                    setTimeout(() => {
                        //获取label容器视图矩形数据
                        this.modelViewerRect = this.getModelViewer().getBoundingClientRect()
                        this.onRecoverModel()
                        this.registerHotspotList()//注册热点列表
                        //初始化模型label矩形
                        this.hotspotLabelRects = Map
                        //按动画形式执行画线方法
                        const startSVGRenderLoop = () => {
                            if (this.modelInfo.showHotspotEnable) {
                                //查找所有热点数据并遍历
                                this.modelInfo.hotspotList.forEach((item, index) => {
                                    //查找label
                                    let hotspotLabel = this.getHotspotLabel(item.slot)
                                    //更新矩形
                                    let hotspotLabelRect = this.getBoundingClientRect(hotspotLabel)
                                    this.hotspotLabelRects[hotspotLabel.slot] = hotspotLabelRect
                                    //更新参数
                                    //this.modelInfo.hotspotList[index].labelX = hotspotLabelRect.left / (this.modelViewerRect.width - hotspotLabelRect.width)
                                    //this.modelInfo.hotspotList[index].labelY = hotspotLabelRect.top / (this.modelViewerRect.height - hotspotLabelRect.height)
                                    //画线
                                    this.drawLine(item, this.getHotspotLine(item.slot), hotspotLabel, hotspotLabelRect);
                                })
                            }
                            //console.log(loopTag)
                            requestAnimationFrame(startSVGRenderLoop);
                        };
                        startSVGRenderLoop()
                        this.startViewDisplayAnim()
                    }, 800);
                })
                this.loadCamera()
            },
            //复位模型
            onRecoverModel() {
                this.getModelViewer().fieldOfView = this.modelInfo.fieldOfView
                this.getModelViewer().cameraOrbit = this.modelInfo.cameraOrbit
                this.getModelViewer().cameraTarget = this.modelInfo.cameraTarget
            },
            /////////工具和加载/////////
            //更新标题
            updateOperateTitle() {
                if (!this.debugModel) {
                    this.mainTitle = null
                    return
                }
                if (this.editHotspotModel) {
                    this.mainTitle = '编辑模式'
                } else {
                    this.mainTitle = '预览模式'
                }
            },
            //编辑热点状态更改
            editHotspotModelChange() {
                this.updateOperateTitle();
                if (this.editHotspotModel) {//当是热点编辑时，关闭循环显示热点
                    this.circulateShowHotspot = false
                } else {
                    this.circulateShowHotspot = this.modelInfo.circulateShowHotspot;
                }
            },
            //取消添加编辑热点
            onCancelAddEditHotspot() {
                this.currentEditHotspotInfo = null
                this.editHotspotDialogLabel = null
            },
            //添加热点
            addHotspotInfo(dataSurface) {
                this.currentEditHotspotInfo = {
                    slot: 'hotspot-' + getSecureRandomString(5),
                    dataSurface: dataSurface,
                    cameraOrbit: this.getModelViewer().getCameraOrbit().toString(),
                    fieldOfView: this.getModelViewer().getFieldOfView() + 'deg',
                    cameraTarget: this.getModelViewer().getCameraTarget().toString(),
                    labelX: 0.5,
                    labelY: 0.5
                }
                this.editHotspotDialogLabel = '新增热点'
            },
            //编辑热点
            editHotspotInfo(hotspotInfo) {
                this.currentEditHotspotInfo = hotspotInfo
                this.editHotspotDialogLabel = '编辑热点'
            },
            //保存热点
            onSaveHotspot() {
                if (!this.currentEditHotspotInfo) {
                    return
                }
                if (!this.modelInfo.hotspotList) {
                    this.modelInfo.hotspotList = []
                }
                const index = this.modelInfo.hotspotList.findIndex(item => item === this.currentEditHotspotInfo);
                if (index === -1) {
                    //找不到则添加
                    this.modelInfo.hotspotList.push(this.currentEditHotspotInfo)
                }
                this.currentEditHotspotInfo = null
                requestAnimationFrame(() => {
                    this.registerHotspotList()
                });
            },
            //移除热点
            onRemoveHotspot(hotspotInfo) {
                const index = this.modelInfo.hotspotList.findIndex(item => item === hotspotInfo);
                if (index === -1) {
                    return
                }
                const confirmRemove = confirm('确定要移除该热点吗？');
                if (confirmRemove) {
                    this.modelInfo.hotspotList.splice(index, 1);
                }
            },
            //加载模型数据
            onLoadModel(modelInfoStr) {
                let modelInfoJson = null
                if (modelInfoStr != null) {
                    modelInfoJson = decodeURIComponent(modelInfoStr)
                }
                if (modelInfoJson != null && modelInfoJson.length > 0) {
                    this.modelInfo = JSON.parse(modelInfoJson)
                    //console.log(this.modelInfo)
                } else {
                    this.modelInfo = {
                        showCameraView: false,//显示相机
                        showHotspotEnable: true,//启用热点
                        circulateShowHotspot: false,//循环播放热点
                        pathByHtml: '../assets/models/grogu.glb',
                        cameraOrbit: 'auto',
                        fieldOfView: 'auto',
                        cameraTarget: 'auto',
                        opacityAnimInitialDelay: 5000,
                        opacityAnimPeriod: 0,
                        hotspotList: [
                            {
                                title: '耳朵',
                                introduction: '',
                                slot: 'hotspot-0',
                                dataSurface: '0 1 16966 16962 16965 0.008 0.823 0.168',
                                cameraOrbit: '0.3291481682644898rad 1.2626970400778976rad 1.8763722296721423m',
                                fieldOfView: '12.860682608585783deg',
                                cameraTarget: '-0.03719583555898032m 0.18190251745237637m 0.017868775320697063m',
                                labelX: 0.9449591280653951,
                                labelY: 0.06288819875776397
                            },
                        ]
                    }
                }
                //初始化
                this.showCameraView = this.modelInfo.showCameraView
                this.circulateShowHotspot = this.modelInfo.circulateShowHotspot
                this.updateStatusByDebug();
            },
            //此处在移动端有点兼容性问题
            getBoundingClientRect(child) {
                const childRect = child.getBoundingClientRect();
                const revealRect = this.getModelViewer().getBoundingClientRect();
                //console.log(childRect)
                let boundingClientRect = {
                    left: childRect.left - revealRect.left + this.getModelViewer().scrollLeft,
                    top: childRect.top - revealRect.top + this.getModelViewer().scrollTop,
                    right: childRect.right - revealRect.left + this.getModelViewer().scrollLeft,
                    bottom: childRect.bottom - revealRect.top + this.getModelViewer().scrollTop,
                    width: childRect.width,
                    height: childRect.height
                }
                return boundingClientRect;
            },
            //调试模式点击
            onDebugClick() {
                if (this.debugClickCountProxy == null) {
                    this.debugClickCountProxy = new ClickCountProxy()
                    this.debugClickCountProxy.setOnExecuteListener(() => {
                        this.debugModel = !this.debugModel
                        console.log(`调试模式点击：${this.debugModel}`)
                        this.updateStatusByDebug()
                    })
                }
                this.debugClickCountProxy.clickCall()
            },
            //根据debug模式更新状态
            updateStatusByDebug() {
                if (!this.debugModel) {//不是debug模式关闭热点编辑
                    this.editHotspotModel = false
                }
                this.editHotspotModelChange()
            },
            //打印配置
            onPrintConfig() {
                console.log('cameraOrbit: "' + this.getModelViewer().getCameraOrbit() + '",\n'
                    + 'fieldOfView: "' + this.getModelViewer().getFieldOfView() + 'deg' + '",\n'
                    + 'cameraTarget: "' + this.getModelViewer().getCameraTarget() + '",')
            }
        }
    })
</script>
</html>